from flask_wtf import FlaskForm
from wtforms import StringField, TextAreaField, SelectField, IntegerField, DateField, FileField, PasswordField, BooleanField
from wtforms.validators import DataRequired, Length, Email, Regexp, NumberRange, Optional, EqualTo
from wtforms.widgets import TextArea
from werkzeug.utils import secure_filename
import re


class UserProfileForm(FlaskForm):
    """用户资料表单"""
    username = StringField('用户名', validators=[
        DataRequired(message='用户名不能为空'),
        Length(min=3, max=20, message='用户名长度必须在3-20个字符之间'),
        Regexp(r'^[a-zA-Z0-9_]+$', message='用户名只能包含字母、数字和下划线')
    ])
    
    email = StringField('邮箱', validators=[
        DataRequired(message='邮箱不能为空'),
        Email(message='请输入有效的邮箱地址')
    ])
    
    nickname = StringField('昵称', validators=[
        DataRequired(message='昵称不能为空'),
        Length(min=2, max=30, message='昵称长度必须在2-30个字符之间')
    ])
    
    bio = TextAreaField('个人简介', validators=[
        Length(max=500, message='个人简介不能超过500个字符')
    ])
    
    age = IntegerField('年龄', validators=[
        NumberRange(min=18, max=100, message='年龄必须在18-100之间')
    ])
    
    gender = SelectField('性别', choices=[
        ('', '请选择'),
        ('male', '男'),
        ('female', '女'),
        ('other', '其他')
    ], validators=[
        DataRequired(message='请选择性别')
    ])
    
    phone = StringField('手机号', validators=[
        Regexp(r'^1[3-9]\d{9}$', message='请输入有效的手机号')
    ])
    
    birth_date = DateField('出生日期', validators=[
        Optional()
    ])
    
    address = StringField('地址', validators=[
        Length(max=200, message='地址不能超过200个字符')
    ])
    
    avatar = FileField('头像', validators=[
        Optional()
    ])
    
    interests = StringField('兴趣爱好', validators=[
        Length(max=200, message='兴趣爱好不能超过200个字符')
    ])
    
    website = StringField('个人网站', validators=[
        Optional(),
        Regexp(r'^https?://', message='网站地址必须以http://或https://开头')
    ])
    
    is_public = BooleanField('公开个人资料')


class UserRegistrationForm(FlaskForm):
    """用户注册表单"""
    username = StringField('用户名', validators=[
        DataRequired(message='用户名不能为空'),
        Length(min=3, max=20, message='用户名长度必须在3-20个字符之间'),
        Regexp(r'^[a-zA-Z0-9_]+$', message='用户名只能包含字母、数字和下划线')
    ])
    
    email = StringField('邮箱', validators=[
        DataRequired(message='邮箱不能为空'),
        Email(message='请输入有效的邮箱地址')
    ])
    
    password = PasswordField('密码', validators=[
        DataRequired(message='密码不能为空'),
        Length(min=6, max=20, message='密码长度必须在6-20个字符之间'),
        Regexp(r'^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d]{6,}$', 
               message='密码必须包含至少一个大写字母、一个小写字母和一个数字')
    ])
    
    confirm_password = PasswordField('确认密码', validators=[
        DataRequired(message='请确认密码'),
        EqualTo('password', message='两次输入的密码不一致')
    ])
    
    nickname = StringField('昵称', validators=[
        DataRequired(message='昵称不能为空'),
        Length(min=2, max=30, message='昵称长度必须在2-30个字符之间')
    ])
    
    agree_terms = BooleanField('同意用户协议', validators=[
        DataRequired(message='必须同意用户协议才能注册')
    ])


class UserLoginForm(FlaskForm):
    """用户登录表单"""
    username = StringField('用户名或邮箱', validators=[
        DataRequired(message='用户名或邮箱不能为空')
    ])
    
    password = PasswordField('密码', validators=[
        DataRequired(message='密码不能为空')
    ])
    
    remember_me = BooleanField('记住我')


class FileUploadForm(FlaskForm):
    """文件上传表单"""
    file = FileField('选择文件', validators=[
        DataRequired(message='请选择要上传的文件')
    ])
    
    description = TextAreaField('文件描述', validators=[
        Length(max=500, message='文件描述不能超过500个字符')
    ])


def validate_avatar(form, field):
    """自定义头像验证器"""
    if field.data:
        filename = field.data.filename
        if not filename:
            return False
        
        # 检查文件扩展名
        allowed_extensions = ['jpg', 'jpeg', 'png', 'gif', 'webp']
        if '.' not in filename or filename.rsplit('.', 1)[1].lower() not in allowed_extensions:
            raise ValueError('只允许上传jpg、jpeg、png、gif、webp格式的图片')
        
        # 检查文件大小（假设最大5MB）
        field.data.seek(0, 2)  # 移动到文件末尾
        size = field.data.tell()  # 获取文件大小
        field.data.seek(0)  # 重置文件指针
        
        if size > 5 * 1024 * 1024:  # 5MB
            raise ValueError('头像文件大小不能超过5MB')
    
    return True